package handler

import (
	"crypto/rand"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"errors"
	"net/http"
	"time"

	"github.com/yourusernameapijson-auth/model"
	"apijson-auth/database"
)

// AuthHandler 处理认证相关请求
type AuthHandler struct {
	DB *sql.DB
}

// LoginRequest 登录请求结构
type LoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// LoginResponse 登录响应结构
type LoginResponse struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
	Token   string      `json:"token,omitempty"`
}

// LogoutRequest 登出请求结构
type LogoutRequest struct {
	Token string `json:"token"`
}

// RegisterRequest 注册请求结构
type RegisterRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
	Name     string `json:"name"`
}

// Token 结构
type Token struct {
	ID        int       `json:"id"`
	UserID    int       `json:"user_id"`
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expires_at"`
	CreatedAt time.Time `json:"created_at"`
}

// Login 处理用户登录
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
	// 解析请求体
	var req LoginRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		respondWithError(w, http.StatusBadRequest, "Invalid request body")
		return
	}

	// 验证用户名和密码
	user, err := h.authenticateUser(req.Username, req.Password)
	if err != nil {
		respondWithError(w, http.StatusUnauthorized, "Invalid credentials")
		return
	}

	// 生成令牌
	token, err := h.generateToken(user.ID)
	if err != nil {
		respondWithError(w, http.StatusInternalServerError, "Failed to generate token")
		return
	}

	// 返回响应
	respondWithJSON(w, http.StatusOK, LoginResponse{
		Code:    http.StatusOK,
		Message: "Login successful",
		Token:   token.Token,
		Data: map[string]interface{}{
			"user_id": user.ID,
			"name":    user.Name,
			"role":    user.Role,
		},
	})
}

// Logout 处理用户登出
func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
	// 从Authorization头获取令牌
	tokenString := r.Header.Get("Authorization")
	if tokenString == "" {
		respondWithError(w, http.StatusBadRequest, "Authorization token required")
		return
	}

	// 使令牌失效
	if err := h.invalidateToken(tokenString); err != nil {
		respondWithError(w, http.StatusInternalServerError, "Failed to logout")
		return
	}

	respondWithJSON(w, http.StatusOK, Response{
		Code:    http.StatusOK,
		Message: "Logout successful",
	})
}

// Register 处理用户注册
func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
	// 解析请求体
	var req RegisterRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		respondWithError(w, http.StatusBadRequest, "Invalid request body")
		return
	}

	// 验证输入
	if req.Username == "" || req.Password == "" || req.Name == "" {
		respondWithError(w, http.StatusBadRequest, "Username, password and name are required")
		return
	}

	// 检查用户名是否已存在
	var count int
	err := h.DB.QueryRow("SELECT COUNT(*) FROM User WHERE name = ?", req.Username).Scan(&count)
	if err != nil {
		respondWithError(w, http.StatusInternalServerError, "Database error")
		return
	}
	if count > 0 {
		respondWithError(w, http.StatusConflict, "Username already exists")
		return
	}

	// 创建用户
	hashedPassword, err := hashPassword(req.Password)
	if err != nil {
		respondWithError(w, http.StatusInternalServerError, "Failed to hash password")
		return
	}

	result, err := h.DB.Exec(
		"INSERT INTO User(name, password, role) VALUES(?, ?, ?)",
		req.Username,
		hashedPassword,
		model.LOGIN, // 默认角色
	)
	if err != nil {
		respondWithError(w, http.StatusInternalServerError, "Failed to create user")
		return
	}

	userID, err := result.LastInsertId()
	if err != nil {
		respondWithError(w, http.StatusInternalServerError, "Failed to get user ID")
		return
	}

	respondWithJSON(w, http.StatusCreated, Response{
		Code:    http.StatusCreated,
		Message: "User registered successfully",
		Data: map[string]interface{}{
			"user_id": userID,
		},
	})
}

// authenticateUser 验证用户凭据
func (h *AuthHandler) authenticateUser(username, password string) (*model.User, error) {
	var user model.User
	var hashedPassword string

	// 查询用户
	err := h.DB.QueryRow(
		"SELECT id, name, role, password FROM User WHERE name = ?",
		username,
	).Scan(&user.ID, &user.Name, &user.Role, &hashedPassword)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, errors.New("user not found")
		}
		return nil, err
	}

	// 验证密码
	if !checkPasswordHash(password, hashedPassword) {
		return nil, errors.New("invalid password")
	}

	return &user, nil
}

// generateToken 生成并存储新的访问令牌
func (h *AuthHandler) generateToken(userID int) (*Token, error) {
	// 生成随机令牌
	tokenBytes := make([]byte, 32)
	if _, err := rand.Read(tokenBytes); err != nil {
		return nil, err
	}
	token := base64.URLEncoding.EncodeToString(tokenBytes)

	// 设置过期时间 (24小时后)
	expiresAt := time.Now().Add(24 * time.Hour)

	// 存储令牌
	_, err := h.DB.Exec(
		"INSERT INTO Token(user_id, token, expires_at) VALUES(?, ?, ?)",
		userID,
		token,
		expiresAt,
	)
	if err != nil {
		return nil, err
	}

	return &Token{
		UserID:    userID,
		Token:     token,
		ExpiresAt: expiresAt,
		CreatedAt: time.Now(),
	}, nil
}

// invalidateToken 使令牌失效
func (h *AuthHandler) invalidateToken(tokenString string) error {
	// 从数据库删除令牌
	_, err := h.DB.Exec("DELETE FROM Token WHERE token = ?", tokenString)
	return err
}

// ValidateToken 验证令牌有效性
func (h *AuthHandler) ValidateToken(tokenString string) (*model.User, error) {
	var token Token
	var user model.User

	// 查询令牌
	err := h.DB.QueryRow(
		"SELECT t.id, t.user_id, t.token, t.expires_at, t.created_at, u.id, u.name, u.role "+
			"FROM Token t JOIN User u ON t.user_id = u.id "+
			"WHERE t.token = ? AND t.expires_at > NOW()",
		tokenString,
	).Scan(
		&token.ID, &token.UserID, &token.Token, &token.ExpiresAt, &token.CreatedAt,
		&user.ID, &user.Name, &user.Role,
	)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, errors.New("invalid or expired token")
		}
		return nil, err
	}

	return &user, nil
}

// hashPassword 密码哈希处理
func hashPassword(password string) (string, error) {
	// 实际项目中应该使用bcrypt或argon2等安全哈希算法
	// 这里简化处理，仅做示例
	return password, nil
}

// checkPasswordHash 验证密码哈希
func checkPasswordHash(password, hash string) bool {
	// 实际项目中应该使用bcrypt或argon2等安全哈希算法
	// 这里简化处理，仅做示例
	return password == hash
}

// respondWithError 返回错误响应
func respondWithError(w http.ResponseWriter, code int, message string) {
	respondWithJSON(w, code, Response{
		Code:    code,
		Message: message,
	})
}

// respondWithJSON 返回JSON响应
func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)
	json.NewEncoder(w).Encode(payload)
}
